package com.soo.hoo.admin.service.impl;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.soo.hoo.admin.mapper.*;
import com.soo.hoo.admin.model.dto.UserDTO;
import com.soo.hoo.admin.model.entity.*;
import com.soo.hoo.admin.model.vo.UserVO;
import com.soo.hoo.admin.service.UserService;
import com.soo.hoo.admin.utils.SaLoginUtil;
import com.soo.hoo.core.constant.Constants;
import com.soo.hoo.core.exception.GlobalException;
import com.soo.hoo.core.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户管理
 * </p>
 *
 * @author 杨燚
 * @since 2022/2/21
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements UserService, StpInterface {

    private final SysRoleMapper roleMapper;
    private final SysUserRoleMapper userRoleMapper;
    private final SysPermissionMapper permissionMapper;
    private final SysRolePermissionMapper rolePermissionMapper;

    @Override
    public UserVO login(UserDTO user) {
        LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysUser::getUsername, user.getUsername());
        SysUser sysUser = baseMapper.selectOne(lqw);
        if (sysUser == null) {
            throw new GlobalException("账户或密码不正确");
        }
        if (!user.getPassword().equals(sysUser.getPassword())) {
            throw new GlobalException("账户或密码不正确");
        }
        StpUtil.login(sysUser.getId());
        UserVO loginUser = UserVO.builder()
                .id(sysUser.getId())
                .token(StpUtil.getTokenInfo().getTokenValue())
                .name(sysUser.getName())
                .username(sysUser.getUsername())
                .avatar(sysUser.getAvatarUrl())
                .build();
        // 返回用户的菜单权限
        List<SysPermission> permissions = listPermission(sysUser.getId());
        if (permissions != null) {
            List<SysPermission> menus = permissions.stream().filter(e -> e.getType() == 1).toList();
            List<TreeNode<Long>> menuNodes = buildTreeNodes(menus);
            List<Tree<Long>> menuTree = TreeUtil.build(menuNodes, Constants.ROOT_ID);
            loginUser.setMenuTree(menuTree);

            List<SysPermission> perms = permissions.stream().filter(e -> e.getType() == 2).toList();
            loginUser.setPermissionList(perms);
        }
        return loginUser;
    }

    @Override
    public UserVO login(String phoneNo) {
        LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUsername, phoneNo);
        SysUser sysUser = baseMapper.selectOne(lqw);
        if (sysUser == null) {
            sysUser = new SysUser();
            sysUser.setName(IdUtil.nanoId(6) + StrUtil.sub(phoneNo, 6, phoneNo.length() - 1));
            sysUser.setUsername(phoneNo);
            sysUser.setPassword("123456");
            sysUser.setPhoneNumber(phoneNo);
            sysUser.setUserSource(2);
            baseMapper.insert(sysUser);
        }
        StpUtil.login(sysUser.getId());
        UserVO vo =  UserVO.builder()
                .id(sysUser.getId())
                .token(StpUtil.getTokenInfo().getTokenValue())
                .name(sysUser.getName())
                .username(sysUser.getUsername())
                .nickname(sysUser.getNickname())
                .phoneNumber(sysUser.getPhoneNumber())
                .avatar(sysUser.getAvatarUrl())
                .build();
        SaLoginUtil.login(vo);
        return vo;
    }

    @Override
    public void checkToken(String tokenValue) {
        try {
            StpUtil.checkLogin();
            if (StrUtil.isBlank(tokenValue) || !tokenValue.equals(StpUtil.getTokenValue())) {
                throw new NotLoginException("", "", NotLoginException.INVALID_TOKEN);
            }
        } catch (NotLoginException e) {
            String type = e.getType();
            String message;
            if (NotLoginException.NOT_TOKEN.equals(type)) {
                message = "尚未登录，请先登录";
            } else if (NotLoginException.INVALID_TOKEN.equals(type)) {
                message = "无效的登录信息，请重新登录";
            } else if (NotLoginException.TOKEN_TIMEOUT.equals(type)) {
                message = "登录已过期，请重新登录";
            } else if (NotLoginException.BE_REPLACED.equals(type)) {
                message = "登录已过期，请重新登录";
            } else if (NotLoginException.KICK_OUT.equals(type)) {
                message = "登录已过期，请重新登录";
            } else {
                message = "尚未登录，请先登录";
            }
            throw new GlobalException(401, message);
        }
    }

    @Override
    public void logout(Long userId) {
        if (userId != null) {
            StpUtil.logout(userId);
        } else {
            StpUtil.logout();
        }
    }

    @Override
    public void initUser() {
        LambdaQueryWrapper<SysUser> userLqw = new LambdaQueryWrapper<>();
        userLqw.eq(SysUser::getUsername, Constants.ADMIN);
        SysUser user = baseMapper.selectOne(userLqw);
        if (user == null) {
            // 用户-超管
            user = new SysUser();
            user.setName("超级管理员");
            user.setUsername(Constants.ADMIN);
            // 密码和用户名一样
            user.setPassword(Constants.ADMIN);
            user.setPhoneNumber("18300885220");
            user.setEmail("1361666560@qq.com");
            baseMapper.insert(user);
        }
        LambdaQueryWrapper<SysRole> roleLqw = new LambdaQueryWrapper<>();
        roleLqw.eq(SysRole::getRoleName, Constants.ADMIN_ROLE);
        SysRole role = roleMapper.selectOne(roleLqw);
        if (role == null) {
            // 角色-超管
            role = new SysRole();
            role.setRoleName(Constants.ADMIN_ROLE);
            role.setDescription("超级管理员");
            role.setEnabled(true);
            role.setSuperRole(true);
            roleMapper.insert(role);

            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(role.getId());
            userRoleMapper.insert(userRole);
        }
    }


    @Override
    public UserVO getUserInfo(Long userId) {
        SysUser sysUser = baseMapper.selectById(userId);
        if (sysUser == null) {
            throw new GlobalException(400, "用户不存在，无法获取用户信息");
        }
        return UserVO.builder()
                .id(sysUser.getId())
                .token(StpUtil.getTokenInfo().getTokenValue())
                .username(sysUser.getUsername())
                .avatar(String.valueOf(sysUser.getAvatarId()))
                .build();
    }

    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        List<SysPermission> permissions = listPermission(loginId);
        if (permissions == null) {
            return null;
        }
        return permissions.stream().map(SysPermission::getPermissionName).collect(Collectors.toList());
    }

    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        LambdaQueryWrapper<SysUserRole> lqw = new LambdaQueryWrapper<SysUserRole>()
                .eq(SysUserRole::getUserId, loginId);
        List<SysUserRole> userRoles = userRoleMapper.selectList(lqw);
        if (CollUtil.isNotEmpty(userRoles)) {
            Set<Long> roleIds = userRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet());
            List<SysRole> roles = roleMapper.selectBatchIds(roleIds);
            return roles.stream().map(SysRole::getRoleName).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 获取用户所有的权限列表
     *
     * @param loginId 登录id，当前用户id
     * @return 用户权限列表
     */
    private List<SysPermission> listPermission(Object loginId) {
        LambdaQueryWrapper<SysUserRole> lqw = new LambdaQueryWrapper<SysUserRole>()
                .eq(SysUserRole::getUserId, loginId);
        List<SysUserRole> userRoles = userRoleMapper.selectList(lqw);
        if (CollUtil.isNotEmpty(userRoles)) {
            Set<Long> roleIds = userRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet());
            List<SysRole> roles = roleMapper.selectBatchIds(roleIds);
            if (roles.stream().anyMatch(e -> e.getRoleName().equals(Constants.ADMIN_ROLE))) {
                return permissionMapper.selectList(Wrappers.emptyWrapper());
            }
            LambdaQueryWrapper<SysRolePermission> in = new LambdaQueryWrapper<SysRolePermission>()
                    .in(SysRolePermission::getRoleId, roleIds);
            List<SysRolePermission> rolePermissions = rolePermissionMapper.selectList(in);
            if (CollUtil.isNotEmpty(rolePermissions)) {
                Set<Long> permissionIds = rolePermissions.stream()
                        .map(SysRolePermission::getPermissionId).collect(Collectors.toSet());
                return permissionMapper.selectBatchIds(permissionIds);
            }
        }
        return null;
    }

    @Override
    public void verifyUser(String userName) {
        LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUsername, userName)
                .eq(SysUser::getDeleted, "0");
        List<SysUser> users = baseMapper.selectList(lqw);
        if (CollUtil.isNotEmpty(users)) {
            throw new GlobalException("用户【" + userName + "】已存在，");
        }
    }


    /**
     * 构建菜单的树结构节点
     *
     * @param menus 菜单列表
     * @return 树结构节点
     */
    private static List<TreeNode<Long>> buildTreeNodes(List<SysPermission> menus) {
        List<TreeNode<Long>> menuNodes = new ArrayList<>();
        for (SysPermission menu : menus) {
            TreeNode<Long> node = new TreeNode<>();
            node.setId(menu.getId());
            node.setName(menu.getPermissionName());
            node.setParentId(menu.getParentId());
            node.setWeight(menu.getWeight());
            Map<String, Object> extra = new HashMap<>();
            extra.put("iconName", menu.getIconName());
            extra.put("iconColor", menu.getIconColor());
            extra.put("url", menu.getUrl());
            extra.put("description", menu.getDescription());
            node.setExtra(extra);
            menuNodes.add(node);
        }
        return menuNodes;
    }

}
